/**
 * list controller
 */

import Promise from 'bluebird';
import BaseController from './base';

const parseInt = function(inp) {
    return Math.floor(+inp || 0);
};
const parseDateBySecond = function(inp) {
    if(!inp && inp !== 0) {
        return inp;
    }

    return new Date(1000 * parseInt(inp));
};

const listBaseOptions = {
    data() {
        return {
            query: {},
            queryParsers: {
                start_time: parseDateBySecond,
                end_time: parseDateBySecond,
                page_size: parseInt,
                page_num: parseInt
            },
            querySearch: {
                auto: true,
                key: 'q'
            },
            queryKeepPageKeys: [
                'page_num', 'page_size',
                'sort'
            ],
            itemsData: {
                pagination: {},
                items: []
            },

            selectedItems: []
        };
    },
    methods: {
        syncQuery() {
            const routeQuery = this.$route.query;
            const queryParsers = this.queryParsers;

            Object.keys(routeQuery).forEach(k => {
                let val = routeQuery[k];
                let parser = queryParsers[k];

                if(parser) {
                    val = parser(val);
                }

                this.query[k] = val;
            });

            if(!this._queryWatched) {
                setTimeout(() => {
                    this.initQueryWatch();
                }, 0);
            }

            this.loadItems();
        },
        initQueryWatch() {
            if(this._queryWatched) {
                return;
            }
            this._queryWatched = true;

            const formatQuery = this.formatQuery;
            const queryKeepPageKeys = this.queryKeepPageKeys;
            const querySearch = this.querySearch || {};
            const keys = Object.keys(this.query);
            const createLoader = (delay) => {
                return () => {
                    clearTimeout(this._reloadTimer);

                    this._reloadTimer = setTimeout(() => {
                        this.$router.push({
                            query: formatQuery(this.query)
                        });
                    }, delay);
                };
            };
            const getQueryStringByKeys = function(query, keys) {
                query = formatQuery(query);

                return keys.map(k => {
                    return `${k}${query[k] || ''}`;
                })
                .join('');
            };

            // search
            if(
                querySearch.key &&
                querySearch.auto &&
                keys.indexOf(querySearch.key) > -1
            ) {
                const delay = +querySearch.delay || 256;

                this.$watch(`query.${querySearch.key}`, createLoader(delay));
            }

            // page
            const pageKeepKeys = keys.filter(k => {
                return queryKeepPageKeys.indexOf(k) < 0;
            });
            if(pageKeepKeys.length) {
                const getPageQueryString = function(query) {
                    return getQueryStringByKeys(query, pageKeepKeys);
                };

                this.$watch(() => {
                    return getPageQueryString(this.query);
                }, () => {
                    this.query.page_num = 1;
                });
            }

            // reload
            const reloadWatchKeys = keys.filter(key => {
                return !querySearch.key || key !== querySearch.key;
            });
            if(reloadWatchKeys.length) {
                const getQueryString = function(query) {
                    return getQueryStringByKeys(query, reloadWatchKeys);
                };

                this.$watch(() => {
                    return getQueryString(this.query);
                }, createLoader(16));
            }
        },

        formatQuery(query) {
            if(!query) {
                query = this.query || {};
            }

            const ret = {};

            Object.keys(query).forEach(k => {
                let val = query[k];

                if(val instanceof Date) {
                    val = Math.floor(val.getTime() / 1000);
                }

                ret[k] = val;
            });

            return ret;
        },
        beforeLoadItems() {},
        afterLoadItems() {},
        loadItems() {
            return Promise.try(() => {
                return this.beforeLoadItems();
            })
            .then(() => {
                return this.formatQuery();
            })
            .then(query => {
                this.itemsData = this.ListModel.query(query);

                return this.itemsData.$promise;
            })
            .tap(() => {
                return this.afterLoadItems();
            });
        },

        removeItem(item) {
            return this.ListModel.delete({
                id: item.id
            })
            .$promise;
        },
        deleteItem(item) {
            return this.$confirm('确认删除此记录？')
            .then(() => {
                return this.removeItem(item);
            })
            .then(() => {
                return this.loadItems();
            })
            .catch(err => {
                if(err === 'cancel') {
                    return;
                }

                throw err;
            });
        },
        setItem(item, data) {
            data = Object.assign({
                id: item.id
            }, data);

            return this.ListModel.update(data).$promise;
        },
        setItems(items, data, {confirm, reload = true} = {}) {
            return Promise.try(() => {
                if(confirm) {
                    return this.$confirm(confirm);
                }
            })
            .then(() => {
                return items;
            })
            .map(item => {
                return this.setItem(item, data);
            })
            .tap(() => {
                if(reload) {
                    return this.loadItems();
                }
            })
            .catch(err => {
                if(err !== 'cancel') {
                    throw err;
                }
            });
        },

        pushItem(item) {
            return this.setItems([item], {
                status: this.statusMap.ONLINE
            });
        },
        pullItem(item) {
            return this.setItems([item], {
                status: this.statusMap.OFFLINE
            });
        },
        pushItems() {
            return this.setItems(this.selectedItems, {
                status: this.statusMap.ONLINE
            }, {
                confirm: '确认上架选中项？'
            });
        },
        pullItems() {
            return this.setItems(this.selectedItems, {
                status: this.statusMap.OFFLINE
            }, {
                confirm: '确认下架选中项？'
            });
        },

        onSortItems({prop, order}) {
            let sort = '';
            if(prop && order) {
                sort = `${prop}-${order !== 'ascending' ? 'desc' : 'asc'}`;
            }

            this.query.sort = sort;
        },

        onPageChange(num) {
            this.query.page_num = +num || 1;
        },
        onSelect(items) {
            this.selectedItems = items;
        }
    },

    watch: {
        $route() {
            this.syncQuery();
        }
    },

    created() {
        this.syncQuery();
    }
};

class ListController extends BaseController {
    constructor(options) {
        const ret = super(options);

        if(!ret.mixins) {
            ret.mixins = [];
        }

        ret.mixins.push(listBaseOptions);

        return ret;
    }
}

export default ListController;
